﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Timers;

namespace DongleTest
{
    public class CCDebugger
    {
        //private Timer mytimer = new Timer();
        private string oldMac = string.Empty;
        private static string exePath = string.Empty;
        private string target = string.Empty;
        private string actions = string.Empty;
        public string file = string.Empty;
        private string interfaceSlow = string.Empty;
        private string change = string.Empty;
        private string flashlock = string.Empty;
        private string bootloaderID = string.Empty;
        private string ID = string.Empty;

        public CCDebugger(string id, string hexPath)
        {
            ID = id;
            file = hexPath.Trim();

            if (System.IO.File.Exists(@"C:\Program Files (x86)\Texas Instruments\SmartRF Tools\Flash Programmer\bin\SmartRFProgConsole.exe"))
            {
                exePath = @"C:\Program Files (x86)\Texas Instruments\SmartRF Tools\Flash Programmer\bin\SmartRFProgConsole.exe";
            }
            else
            {
                exePath = @"C:\Program Files\Texas Instruments\SmartRF Tools\Flash Programmer\bin\SmartRFProgConsole.exe";
            }

            //mytimer.Interval = 500;
            //mytimer.Elapsed += mytimer_Elapsed;
            //mytimer.Start();
        }

        //private void mytimer_Elapsed(object sender, ElapsedEventArgs e)
        //{
        //    string mac = ReadMac();
        //    if (!"ERROR".Equals(mac) && !mac.Equals(oldMac))
        //    {
        //        oldMac = mac;
        //        if (MacChanged != null)
        //        {
        //            MacChanged.Invoke(this, mac);
        //        }
        //    }

        //}

        private class ReturnCodes
        {
            public const int Success = 0;
            public const int SystemError = 1;
            public const int ParameterError = 2;
            public const int IllegalParameterCombinations = 3;
            public const int MissingParameters = 4;
            public const int MissingImageFileOrCommunicationError = 5;
        }

        private class Target
        {
            public const string S = "S";
            public const string AU = "AU";
            public const string AS = "AS";
            public const string B = "B";
        }

        private class Actions
        {
            public const string P = "P";
            public const string EP = "EP";
            public const string EPV = "EPV";
            public const string EPVC = "EPVC";
            public const string PV = "PV";
            public const string PVC = "PVC";
            public const string V = "V";
            public const string VC = "VC";
            public const string R = "R";
            public const string RP = "RP";
            public const string WP = "WP";
            public const string EWP = "EWP";
            public const string CE = "CE";
        }

        private class FlashLock
        {
            public const string L = "L";
            public const string LB = "LB";
            public const string LD = "LD";
            public const string LA = "LA";
            public const string LP = "LP";
            public const string LPD = "LPD";
        }

        private string GetParam()
        {
            string param = string.Empty;
            if (!string.IsNullOrEmpty(target))
            {
                param += target;
            }

            if (!string.IsNullOrEmpty(actions))
            {
                param += " " + actions;
            }

            if (!string.IsNullOrEmpty(file))
            {
                param += " F=" + file;
            }

            if (!string.IsNullOrEmpty(interfaceSlow))
            {
                param += " " + interfaceSlow;
            }

            if (!string.IsNullOrEmpty(change))
            {
                param += " " + change;
            }

            if (!string.IsNullOrEmpty(flashlock))
            {
                param += " " + flashlock;
            }

            if (!string.IsNullOrEmpty(bootloaderID))
            {
                param += " " + bootloaderID;
            }
            return param;
        }

        private static string StartProcess(string param)
        {
            try
            {
                Process process = new Process
                {
                    StartInfo = { FileName = exePath, Arguments = param, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true }
                };
                process.Start();
                process.WaitForExit();
                string strResult = process.StandardOutput.ReadToEnd();
                Console.WriteLine(strResult);
                return strResult;
            }
            catch (Exception)
            {

                return "";
            }
           
        }

        /// <summary>
        /// 读取MAC
        /// </summary>
        /// <returns></returns>
        public string ReadMac()
        {
            string mac = string.Empty;
            string param = "S(" + ID + ") RI(F=256)";
            string result = StartProcess(param);

            if (result.Contains("IEEE MAC address read successfully"))
            {
                Regex reg = new Regex(@"(?<=IEEE address\: )[a-zA-Z0-9\.]{17}");
                mac = reg.Match(result).Value;
                if (!string.IsNullOrEmpty(mac) && !mac.Equals("00.00.00.00.00.00"))
                {
                    return mac;
                }
            }

            return "ERROR";
        }

        /// <summary>
        /// 擦除
        /// </summary>
        /// <returns></returns>
        public bool Erase()
        {
            string param = "S(" + ID + ") CE";
            string result = StartProcess(param);
            if (result.Contains("Chip erased OK"))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 烧录
        /// </summary>
        /// <returns></returns>
        public bool Program()
        {
            target = Target.S + "(" + ID + ")";
            actions = Actions.EP;
            flashlock = FlashLock.LD;
            string param = GetParam();
            string result = StartProcess(param);
            if (result.Contains("Erase and program OK"))
            {
                return true;
            }
            else
            {
                //string fileName = "E:\\log.txt";
                //FileStream fs = null;
                //if (System.IO.File.Exists(fileName))
                //{
                //    fs = new FileStream(fileName, FileMode.Append);
                //}
                //else
                //{
                //    fs = new FileStream(fileName, FileMode.CreateNew);
                //}

                //StreamWriter sw = new StreamWriter(fs);
                //try
                //{
                //    sw.WriteLine(result);
                //    sw.Close();
                //    fs.Close();
                //}
                //catch (Exception e)
                //{
                //}
                //finally
                //{
                //    sw.Close();
                //    fs.Close();
                //}
            }
            return false;
        }

        public static List<string> Ids()
        {
            if (System.IO.File.Exists(@"C:\Program Files (x86)\Texas Instruments\SmartRF Tools\Flash Programmer\bin\SmartRFProgConsole.exe"))
            {
                exePath = @"C:\Program Files (x86)\Texas Instruments\SmartRF Tools\Flash Programmer\bin\SmartRFProgConsole.exe";
            }
            else
            {
                exePath = @"C:\Program Files\Texas Instruments\SmartRF Tools\Flash Programmer\bin\SmartRFProgConsole.exe";
            }

            List<string> list = new List<string>();
            string param = "X";
            string result = StartProcess(param);
            Regex reg = new Regex("(?<=ID:)[0-9]{4}");
            foreach (Match item in reg.Matches(result))
            {
                list.Add(item.Value);
            }
            return list;
        }

        /*        SmartRFProgConsole [Target][Actions][File][Interface Slow][Change / IEEE address][Flash lock][Bootloader ID]
        The order of the parameters is irrelevant.

        //目标
        Target: [S][AU][AS][B]
        //片上系统（通过USB）S型（n），其中n是董事会的身份证号码，选择一个特定的EB。
        否则，如果有多个板，一个被编程将随机选择。
        S     System-on-Chip (programmed via USB)
              Type S(n), where n is the board ID number, to select a specific EB.
              Otherwise, if there are multiple boards, the one to be programmed will be
              selected at random.
        //电子商务应用（通过USB）型金（n），其中n是董事会的身份证号码，选择一个特定的EB。
        否则，如果有多个板，一个被编程将随机选择。
        AU    EB application (programmed via USB)
              Type AU(n), where n is the board ID number, to select a specific EB.
              Otherwise, if there are multiple boards, the one to be programmed will be
              selected at random.
      
        //电子商务应用（通过EC2适配器串口通讯）。
        （只有smartrf04eb）
        AS(n) EB application (programmed via the EC2 adapter on serial port COMn).
              (only SmartRF04EB)
      
        //EB的bootloader（通过EC2适配器串口通讯）。
        （只有smartrf04eb）
        B(n)  EB bootloader (programmed via the EC2 adapter on serial port COMn).
              (only SmartRF04EB)

        Actions to perform: [P][EP][EPV][EPVC][PV][PVC][V][R][RP][EP][WP][CE]
        P     Program                                                  (all targets)
        EP    Erase and program                                        (all targets)
        EPV   Erase, program and verify                                (all targets)
        EPVC  Erase, program and verify (CRC each page=>faster)        (only target S)
        PV    Program (append) and verify                              (only target S)
        PVC   Program and verify (CRC each page=>faster)               (only target S)
        V     Verify against hex or hem file                         (targets S, AS, B)
        VC    Verify against hex or hem file (CRC each page=>faster) (targets S, AS, B)
        R     Read into hex file                                       (only target S)
        RP=   Read flash page into binary file                         (only target S)
        EP=   Erase flash page                                         (only target S)
        WP=   Write flash page from binary file                        (only target S)
        EWP=  Erase and Write flash page from binary file              (only target S)
        CE    Full chip erase                                          (only target S)

        File: F="f"
        "f"   Flash image file name (intel hex file (*.hex), or hex merge file (*.hem))
              A merge file can contain one or more file/change specifications.
              See "example.hem" for how to create one.

        Interface Slow(Target = S): [IS]
        IS    Program SoC (System on chip) with reduced speed on the debug interface.

        Change hex file before programming (e.g. for serial number): [A=a,D=d][EKF="f"]
        A=a,D=d     Change one or more bytes in the hex file before downloading it.
        a     Hexadecimal address (e.g. 2C03, 01BC25)
        d     One or more bytes to be changed, in hexadecimal format, separated with
              dots (e.g. 4B, 1.2.3.A.B.C, 12.34.56.AB.CD.EF or 12.3.AB)
        EKF   Patch hex file with Encryption Key data.
        "f"   Certificate file from Certicom with encryption key data.

        IEEE MAC address related options [KI(F=f)] [RI(F=f,[PRI][SEC])] [WI(F=f,I=i)]
        (only CC243x, CC253x and CC254x)
        KI(F=f)     Keep the IEEE MAC address currently on the chip when programming it
        RI(F=f,[PRI][SEC]) Read out the IEEE MAC address currently on the chip
               For devices with both a primary and a secondary address, the option "PRI"       or "SEC" can be used to specify which to read. "PRI" is default.
        WI(F=f,I=i) Write the given IEEE MAC address to the chip when programming it
        f     The chip's flash size in kB (only used for CC243x)
              CC243x:  32, 64, or 128  (determines the location of the IEEE address)
              CC253x, CC254x:  set to 0        (not used)
        i     IEEE MAC address to write in hexadecimal format, separated
              with dots (e.g. 00.12.4B.00.00.00.00.01).
              8 bytes for CC243x and CC253x, and 6 bytes for CC254x.

        Flash lock (Target = S): [L(c)][LB(c)][LD(c)][LA(c)][LP(x-y)][LD][LPD(x-y)]
        "L(c), LB(c), LD(c), LA(c)" only CC243x, cc111x and CC251x. "LP(x-y), LD, LPD(x-y)" only CC253x and CC254x
        c     Code for write protection of the upper section of the flash:
              CC111x, CC251x: 0=All, 1=24 kB, 16 kB,  8 kB, 4 kB, 2 kB, 1 kB, 7=None
              CC2430, CC2431: 0=All, 1=64 kB, 32 kB, 16 kB, 8 kB, 4 kB, 2 kB, 7=None
        L(c)     Write protect section only (L(7) is equal to omitting this parameter)
        LB(c)    Write protect section + boot block
        LD(c)    Write protect section, and block debug commands
        LA(c)    Write protect section + boot block, and block debug commands
        LP(x-y)  Write protect flash pages from page x to page y.
                 Several ranges can be given separated with a comma:
                 E.g. LP(0-26,48-126), LP(0,1,2,8-10).
        LD       Block debug commands
        LPD(x-y) Write protect flash pages and block debug commands.

        Bootloader ID (Target = B): I=i
        i     Becomes the EB ID number when programming new bootloader. Use 1-4 digits
              (e.g. 0123, 3, or 45). Important: EBs that are used on the same computer
              must have unique ID numbers!

        Read/Erase/Write Flash page options: RP=n, EWP=n, WP=n, EP=n
        n     The Page number

        Examples:
        SmartRFProgConsole S EPV F=C:\test.hex A=135,D="1 23 45"
        SmartRFProgConsole S P F="C:\test.hex"
        SmartRFProgConsole EPV AU(0123) F=D:\Test.hex
        SmartRFProgConsole B(1) EPV "F=C:\Filename with spaces.hex" I=1234
        SmartRFProgConsole S EP F="C:\Test flash lock.hex" LB(3)
        SmartRFProgConsole S EP F="C:\Test flash lock.hex" LD
        SmartRFProgConsole S EP F="C:\Test flash lock.hex" LP(0-126)
        SmartRFProgConsole S EP F="C:\Test flash lock.hex" LPD(0-126)
        SmartRFProgConsole S EPV F="C:\test.hex" WI(F=0,I=00.12.4B.00.00.00.00.01)
        SmartRFProgConsole S EPV F="C:\test.hex" KI(F=1)
        SmartRFProgConsole S EPV F="C:\test.hex" EKF=certificate_example.txt
        SmartRFProgConsole S PVC F="C:\test.hex"
        SmartRFProgConsole S RP=1 F="C:\test.bin"
        SmartRFProgConsole S EP=1
        SmartRFProgConsole S WP=1 F="C:\test.bin"
        SmartRFProgConsole S EWP=1 F="C:\test.bin"

        To list all connected EBs/programmers (max 64):
        SmartRFProgConsole X

        Status messages are printed to stdout, error messages to stderr.

        Return Codes:
              0 = Success
              1 = System error
              2 = Parameter error
              3 = Illegal parameter combinations
              4 = Missing parameters
              5 = Missing image file or communication error
         */
    }
}
